<template>
  <div class="main">
    <el-card>
        <h3>基础信息</h3>
        <el-form :model="form" :rules="formrules" ref="form" label-width="100px" class="demo-ruleForm">
            <el-form-item label="商品图片" prop="goodsMainImageList" >
                <image-upload :limit="1" v-model="form.goodsMainImageList" />
            </el-form-item>
            <el-form-item label="商品名称" prop="goodsName">
                <el-input v-model="form.goodsName" placeholder="请输入商品名称" style="width:600px"></el-input>
            </el-form-item>
            <el-form-item label="商品分类" prop="categoryId">
                <el-cascader v-model="form.categoryId"  @change="handleChange" :options="cateList" :show-all-levels="false"></el-cascader>
            </el-form-item>
            <h3>规格信息</h3>
            <el-form ref="form" :rules="rules" :model="form">
				<el-form-item label="规格设置" prop="goodsAddSpecDTOList">
					<div style="display: flex;">
						<div>
							<el-button v-for="(item, idx) in default_attr" :key="idx" :disabled="attrBtnDisabled" @click="clickDefaultAttr(item)">{{item}}</el-button>
						</div>

						<el-popover placement="top" width="240" v-model="add_popover_bool" @after-enter="$refs.addValueInput.focus()">
							<div style="display: flex; grid-gap: 10px;">
								<el-input ref="addValueInput" v-model.trim="add_value" @keyup.enter.native="confirm()" />
								<el-button type="primary" @click="confirm()">确定</el-button>
							</div>

							<el-button slot="reference" size="small" type="primary" :disabled="attrBtnDisabled" style="margin-left: 40px;">自定义</el-button>
						</el-popover>
						
						
						<!-- <el-button type="primary" @click="onSubmit()" style="margin-left: 100px;">提交</el-button> -->
					</div>
				</el-form-item>

				<!-- 规格列表 和 表格 -->
				<section style="margin: 0 0 20px 50px;">
					<!-- 展示已经选择的 -->
					<div v-for="(item, index) in form.goodsAddSpecDTOList" :key="index" style="margin-top: 10px;">

						<!-- 属性 -->
						<div>
							<el-input v-model.trim="item.specName" placeholder="属性" style="width: 120px;" @focus="attrFocus(item.attr)" @blur="attrBlur(item.attr)"></el-input>
							<el-button type="danger" size="mini" icon="el-icon-delete" circle @click="deleteAttr(index)"></el-button>
						</div>

						<!-- 属性值 -->
                        <div style="display: flex; margin-top: 10px;">
							<div v-for="(ktem, kndex) in item.specValueList" :key="kndex" style="margin-right: 20px;">
								<el-input size="small" ref="attrValueInput" v-model.trim="item.specValueList[kndex]" placeholder="值" style="width: 100px;" @focus="attrValueFocus(item.specValueList[kndex])" @blur="newAttrValueBlur(item.attr, item.specValueList[kndex])"></el-input>
								<el-button v-if="item.specValueList.length > 1" type="danger" size="mini" icon="el-icon-delete" circle @click="deleteSmall(index, kndex, item.attr, item.specValueList[kndex])" />
							</div>

							<el-button type="primary" size="mini" :disabled="item.specValueList.includes('')" icon="el-icon-plus" @click="addAttributeValue(index)">添加值</el-button>
						</div>
					</div>
                    
					<el-table :data="form.skuList" :span-method="spanMethod" style="margin-top: 20px;" border>
						<template v-for="item_column in table_column">
                            <!-- <el-table-column>
                                {{item_column}}
                            </el-table-column> -->
							<el-table-column v-if="item_column == '图片'" :key="item_column" min-width="150" width="170" align="center" :resizable="false" label="图片">
                                <template slot-scope="{ row, $index }">
									<el-upload class="avatar-uploader" :action="baseUrl+'/platform/file/manage/upload'" :show-file-list="false"
									:data="fileData" :headers="headers" :on-success="(response, res, file) => uploadSkuImg(response, res, file,  $index)"  :before-upload="beforeAvatarUpload">
									<img style="width:100%" v-if="row.skuImage" :src="row.skuImage" class="skuImg" />
									<i v-else class="el-icon-plus avatar-uploader-icon"></i>
									</el-upload>
							    </template>
							</el-table-column>
							<!-- 市场价格 -->
							<el-table-column v-else-if="item_column == 'defaultSalePrice'" :key="item_column"   align="center" :resizable="false" label="售价">
								<template slot-scope="{ row , $index }">
                                    <el-form-item :prop="`skuList.${$index}.defaultSalePrice`" :rules="rules.defaultSalePrice" label-width="0" label=" ">
                                        <el-input v-model="row[item_column]" placeholder="售价" />
                                    </el-form-item>
								</template>
							</el-table-column>
							<!-- 市场价格 -->
							<el-table-column v-else-if="item_column == 'defaultOriginalPrice'" :key="item_column"   align="center" :resizable="false" label="划线价">
								<template slot-scope="{ row , $index }">
									
                                        <el-form-item :prop="`skuList.${$index}.defaultOriginalPrice`" :rules="rules.defaultOriginalPrice" label-width="0" label=" ">
                                            <el-input v-model="row[item_column]" placeholder="划线价" />
                                        </el-form-item>
								</template>
							</el-table-column>
							<!-- 库存 -->
							<el-table-column v-else-if="item_column == 'defaultCostPrice'" :key="item_column" align="center"  :rules="rules.defaultCostPrice" :resizable="false" label="成本价">
								<template slot-scope="{ row, $index }">
									<div style="height: 62px;">
                                        <el-form-item :prop="`skuList.${$index}.defaultCostPrice`" :rules="rules.defaultCostPrice" label-width="0" label=" ">
                                            <el-input v-model="row[item_column]" placeholder="成本价" />
                                        </el-form-item>
									</div>
								</template>
							</el-table-column>
							<el-table-column v-else-if="item_column == 'weight'" :key="item_column" align="center" :resizable="false" label="重量">
								<template slot-scope="{ row }">
									<div style="height: 62px;">
                                        <!-- {{ $index }} -->
										<el-input v-model="row[item_column]" placeholder="重量" />
									</div>
								</template>
							</el-table-column>
							<el-table-column v-else-if="item_column == 'defaultSelected'" :key="item_column" align="center" :resizable="false" label="操作">
								<template slot-scope="{ row   }">
									<div style="height: 62px;">
                                        <el-checkbox  v-model="row[item_column]">默认套餐</el-checkbox>
									</div>
								</template>
							</el-table-column>
							<!-- 其他属性列 -->
							<el-table-column v-else align="center" :resizable="false" :key="item_column" :prop="item_column" :label="item_column" />
						</template>
					</el-table>
				</section>
			</el-form>
            <h3>其他设置</h3>
            <el-form-item label="运费设置" prop="productName">
                <el-radio-group v-model="form.expressFree">
                    <el-radio :label="true">包邮</el-radio>
                    
                  </el-radio-group>
            </el-form-item>
            <el-form-item label="上架设置">
                <el-switch
                class="switchStyle"
                v-model="form.saleFlag"
                active-text="上架"
                inactive-text="下架"
              >
              </el-switch>
            </el-form-item>
            <el-form-item label="商品详情" prop="description">
                <Tinymce :height="200" v-model="form.description"></Tinymce>
            </el-form-item>
            <el-button  @click="cancle()"  >取消</el-button>
            <el-button type="primary" @click="onSubmit()"  >保存</el-button>
        </el-form>
    </el-card>

  </div>
</template>

<script>
import Tinymce from "./tinymce.vue";
import imageUpload from '@/components/uploadImg'
import { getToken } from '@/utils/auth'
import baseUrl from '@/utils/config'
import { allCate ,updateGoods,queryGoodsDetails} from '@/api/goods'
let attr_name_value = new Map([ // Map 数据结构, 根据属性名获取对应属性值 返回数组
    ['默认规格', ['默认值']],
])
let base_column = ['defaultSalePrice', 'defaultOriginalPrice', 'defaultCostPrice','weight','defaultSelected'] // 基本的列
let first_column_rule = [] // 第一列与第二列使用相同的合并规则 (不能存在data中)
let old_attr = '' // 每次当属性获得焦点时都会获取输入框内的值，保存于此
let old_attr_value = '' // 每次当属性值获得焦点时都会获取输入框内的值，保存于此
export default {
  name: '',
  components: { imageUpload ,Tinymce},
  props: {},
  data() {
    return {
        goodsId:null,
        tiny: {
        value: undefined,
      },
        fileData: {   // 接口需要的额外参数
			scene: 'GoodsImage'
	    },
        headers: {  // 请求头部参数
            Authorization:'Bearer '+ getToken()
        },
        cateList:[],
        baseUrl,
        form:{
            goodsMainImageList:'',
            goodsName:'',
            expressFree:true,
            description:'',
            saleFlag:true,
            description:'',
            goodsAddSpecDTOList:[],
            skuList:[],
            categoryId:null
        },
        formrules:{
            goodsMainImageList: [
                { required: true, message: '请上传图片', trigger: 'blur' },
            ],
            goodsName: [
                { required: true, message: '请输入商品名称', trigger: 'blur' },
            ],
            categoryId: [
                { required: true, message: '请选择商品分类', trigger: 'blur' },
            ],
            description: [
                { required: true, message: '请输入商品描述', trigger: 'blur' },
            ],
        },
        imgpath: '',
        default_attr: ['默认规格'], // 默认规格
        table_column: base_column, // 表格列
        add_popover_bool: false, // 添加属性的小弹窗
        add_value: '', // 添加属性的
        // 上边的数据是录入sku相关

        // 表单
        form: {
            goodsMainImageList:'',
            goodsName:'',
            expressFree:true,
            description:'',
            saleFlag:true,
            description:'',
            goodsAddSpecDTOList: [],
            skuList: [], // 表格中的数据
        },

        // 验证规则
        rules: {
            // sku 相关验证
            goodsAddSpecDTOList: {
                validator: (rule, value, callback) => {
                    if (value.length === 0) return callback(new Error('请添加规格'))
                    else return callback()
                },
                trigger: 'blur'
            },
            sku_img: [
                { required: true, message: '图片不能为空', trigger: 'blur' },
                { type: 'string', message: '请等待图片上传完毕', trigger: 'blur' },
            ],
            defaultSalePrice: { required: true, message: '售价不能为空', trigger: 'blur' },
            defaultOriginalPrice: { required: true, message: '划线价不能为空', trigger: 'blur' },
            defaultCostPrice: { required: true, message: '成本价不能为空', trigger: 'blur' },
        }
    }
  },
  watch: {},
  computed: {
    // 已添加的属性(字符串数组)
    selectedAttr() {
        return this.form.goodsAddSpecDTOList.map(x => x.specName)
    },
    // 是否可以添加属性 最多两个属性
    attrBtnDisabled() {
        return false
        return this.form.goodsAddSpecDTOList.length >= 2
    }
},
  methods: {
    getGoodsDetails(id){
        queryGoodsDetails(id).then(res=>{
            this.form = res.data
            this.generateTableColumn()
        })
    },
    // 保存富文本内容-保存字符串
    add() {
      const params = `this.tiny?.value`;
    },
    edit() {
      // 接口回显保存html
      // this.tiny.value = res.data|| ''
    },

    setCardPic(path, pic) {
       this.imgpath = path
     },
     uploadSkuImg(response, res, file,index){
		if (response.code === 200) {
			 this.form.skuList[index]['skuImage'] =response.data
		} else {
			this.$message.error(response.msg)
		}
	},
    async getCate(){
        const cateList = await allCate();
        this.cateList = JSON.parse(JSON.stringify(cateList.data).replace(/id/g, 'value').replace(/categoryName/g, 'label').replace(/childrenCategoryList/g, 'children'))
    },
    handleChange(value) {
        this.form.categoryId = value[1]
      },
        // 图片上传前的判断
    beforeAvatarUpload(file) {
      let imgType = ['jpg', 'jpeg', 'png']
      let judge = false // 后缀
      let type = file.name.split('.')[file.name.split('.').length - 1]
      for (let k = 0; k < imgType.length; k++) {
        if (imgType[k].toUpperCase() === type.toUpperCase()) {
          judge = true
          break
        }
      }
      // 验证图片格式
      if (!judge) {
        this.$message.error('图片格式只支持：JPG、JPEG、PNG')
        return false
      }
      const isLt1M = file.size / 1024 / 1024
      if (isLt1M > 1) {
        this.$message.error('上传头像图片大小不能超过1MB')
        return false
      }
      return true
    },
    // 点击默认的规格按钮
    clickDefaultAttr(attr_name) {
        if (this.selectedAttr.includes(attr_name)) return
        this.form.goodsAddSpecDTOList.push({ specName: attr_name, specValueList: [...attr_name_value.get(attr_name)] }) //解决引用类型导致的问题
        this.generateTableColumn()
        this.traverseSku() // 处理SKU， 生成表格
    },
    // 点击自定义里的确定 添加新的规格
    confirm() {
        if (!this.add_value) return
        this.form.goodsAddSpecDTOList.push({ specName: this.add_value, specValueList: [''] })

        this.generateTableColumn()
        this.traverseSku()

        this.add_popover_bool = false
        this.add_value = ''
    },
    // 属性获得焦点时 得到旧的值 存一下
    attrFocus(oldVal) {
        old_attr = oldVal
    },
    // 属性失去焦点时
    attrBlur(newVal) {
        // 如果 '新值等于旧值' 或者 '空' 什么也不做
        if (newVal === old_attr || newVal === '') return

        // 生成处理表头数据和表格数据
        this.generateTableColumn()
        this.traverseSku()
    },
    // 删除属性
    deleteAttr(idx) {
        this.form.goodsAddSpecDTOList.splice(idx, 1)
        // 生成处理表头数据和表格数据
        this.generateTableColumn()
        this.traverseSku()
    },


    // 添加属性值
    async addAttributeValue(idx) {
        this.form.goodsAddSpecDTOList[idx].specValueList.push('')
        // 让新增的输入框获得焦点
        await this.$nextTick()
        this.$refs.attrValueInput[this.$refs.attrValueInput.length - 1].focus()
    },
    // 属性值获得焦点时 得到旧的值 在输入框失去焦点的时候, 如果值没有变化, 则什么也不做
    attrValueFocus(oldVal) {
        old_attr_value = oldVal
    },
	// 属性值失去焦点时, 操作表格数据 (新版本 可以实现无限个规格)
    newAttrValueBlur(curr_attr, newVal) {
        
        if (newVal === old_attr_value) return

        //  这里根据规格生成的笛卡尔积计算出table中需要改变的行索引 ( 包含新增和修改 )
        let cartesian_arr = this.generateBaseData(this.form.goodsAddSpecDTOList)
        this.form.skuList[0]['defaultSelected'] = true
        
        let change_idx_arr = [] // 需要被改变的行的索引
        for (let i in cartesian_arr) {
            if (cartesian_arr[i][curr_attr] === newVal) change_idx_arr.push(Number(i))
        }
        // 新的表格应该有的长度与现有的表格长度比较, 区分新增还是修改
        let length_arr = this.form.goodsAddSpecDTOList.map(x => x.specValueList.length)
        let new_table_length = length_arr.reduce((acc, curr_item) => acc * curr_item) // 新的表格数据长度 求乘积
        let old_table_length = this.form.skuList.length // 旧的表格数据长度

        // 如果是修改
        if (new_table_length === old_table_length) {
            this.form.skuList.forEach((item, index) => {
                if (change_idx_arr.includes(index)) this.form.skuList[index][curr_attr] = newVal
            })
            return
        }
        // 如果是新增
        if (new_table_length > old_table_length) {
            // 得到当前属性的当前值和其他规格的 goodsAddSpecDTOList, 构造新的表格数据
            let other_goodsAddSpecDTOList = this.form.goodsAddSpecDTOList.map(item => {
                if (item.specName !== curr_attr) return item
                else return { specName: item.specName, specValueList: [newVal] }
            })
            // 得到新增的表格数据
            let ready_map = this.generateBaseData(other_goodsAddSpecDTOList)
            let new_skuList = this.mergeTableData(ready_map)
            change_idx_arr.forEach((item_idx, index) => {
                this.form.skuList.splice(item_idx, 0, new_skuList[index])
            })
        }
    },
    // 删除属性值 四个参数：'一级数组索引', '二级索引', '属性名字', '属性值'  后两个参数用来删除行
    deleteSmall(idx, kdx, attr_name, attr_val) {
        this.form.goodsAddSpecDTOList[idx].specValueList.splice(kdx, 1)

        // 删除table行
        let data_length = this.form.skuList.length
        for (let i = 0; i < data_length; i++) {
            if (this.form.skuList[i][attr_name] == attr_val) {
                this.form.skuList.splice(i, 1)
                i = i - 1
                data_length = data_length - 1
            }
        }
    },

    // 根据 `this.form.goodsAddSpecDTOList` 生成表格列, `table_column` 用于 el-table-column 的 v-for
    async generateTableColumn() {
        this.table_column = this.form.goodsAddSpecDTOList.map(x => x.specName).concat(base_column)
        /*
            不写 `$nextTick`会有bug, 没想明白为啥, 大概是vue懒得更新dom吧
            bug复现方式: 删除`$nextTick`后，勾选颜色，再勾选尺寸，再取消勾选颜色，观察el-table
        */
        await this.$nextTick()
        if (this.form.goodsAddSpecDTOList.length != 0) this.table_column.splice(1, 0, '图片')
    },

    // 合并行
    spanMethod({ row, column, rowIndex, columnIndex }) {
 
        if (columnIndex == 0) {
            let key_0 = column.label
            let first_idx = this.form.skuList.findIndex(x => x[key_0] == row[key_0])
            const calcSameLength = () => this.form.skuList.filter(x => x[key_0] == row[key_0]).length
            first_column_rule = rowIndex == first_idx ? [calcSameLength(), 1] : [0, 0]
            return first_column_rule

            // 第二列的图片与第一列主规格使用相同合并规则 ( 恰好el-table的合并方法是横着走的 )
        } else if (columnIndex == 1) {
            // return first_column_rule

            // 其他列
        } else {
            // 表格数据的每一项, 
            const callBacks = (table_item, start_idx = 0) => {
                if (columnIndex < start_idx) return true
                let curr_key = this.table_column[start_idx]
                return table_item[curr_key] === row[curr_key] && callBacks(table_item, ++start_idx)
            }
            let first_idx = this.form.skuList.findIndex(x => callBacks(x))
            const calcSameLength = () => this.form.skuList.filter(x => callBacks(x)).length
            return rowIndex == first_idx ? [calcSameLength(), 1] : [0, 0]
        }
    },
    // 合并 sku 与 '图片', '销售价格', '库存', '市场价格' , 返回整个表格数据数组
    mergeTableData(arr) {
        return arr.map(item => ({ ...item,  'skuImage': '' ,'defaultSelected':false}))
    },
    // 遍历 `goodsAddSpecDTOList` 生成表格数据
    traverseSku() {
        let ready_map = this.generateBaseData(this.form.goodsAddSpecDTOList)
        this.form.skuList = this.mergeTableData(ready_map)
    },
	// 重新实现笛卡尔积  入参是: this.form.goodsAddSpecDTOList 传入的数组 '为空', '长度为1', '长度大于1' 三种情况 分别处理
    generateBaseData(arr) {
        if (arr.length === 0) return []
        if (arr.length === 1) {
            let [item_spec] = arr
            return item_spec.specValueList.map(x => {
                return {
                    [item_spec.specName]: x
                }
            })
        }
        if (arr.length >= 1) {
            return arr.reduce((accumulator, spec_item) => {
                let acc_value_list = Array.isArray(accumulator.specValueList) ? accumulator.specValueList : accumulator
                let item_value_list = spec_item.specValueList
                let result = []
                for (let i in acc_value_list) {
                    for (let j in item_value_list) {
                        let temp_data = {}
                        // 如果是对象
                        if (acc_value_list[i].constructor === Object) {
                            temp_data = {
                                ...acc_value_list[i],
                                [spec_item.attr]: item_value_list[j]
                            }

                            // 否则如果是字符串
                        } else {
                            temp_data[accumulator.attr] = acc_value_list[i]
                            temp_data[spec_item.attr] = item_value_list[j]
                        }
                        result.push(temp_data)
                    }
                }
                return result
            })
        }
    },
    cancle(){
        this.$router.go(-1)
    },
    onSubmit() {
        this.$refs.form.validate(async (valid, object) => {
            if (!valid) {
                // 获取元素距离body顶部的距离
                // let getTop = dom => {
                // 	let top = dom.offsetTop
                // 	// while括号里的值是 dom.offsetParent
                // 	while (dom = dom.offsetParent) top = top + dom.offsetTop
                // 	return top
                // }
                // let [first_prop] = Object.keys(object)
                // let top = getTop(document.querySelector(`label[for='${first_prop}']`))
                // window.scrollTo({ top: top - 70, behavior: 'smooth' })
                return
            }
            this.form.id = this.goodsId
            let arr = JSON.parse(JSON.stringify(this.form).replace(/attr/g, 'specName').replace(/valueList/g, 'specValueList'))   
            const loading = this.$loading({
                lock: true,
                text: 'Loading',
                spinner: 'el-icon-loading',
                background: 'rgba(0, 0, 0, 0.7)'
            });
            updateGoods(arr).then(res=>{
                loading.close();
                this.$router.back()
                this.$message({
                    message: res.message,
                    type: 'success'
                });
            })
            this.btn_loading = true

        })
    },
	
  },
  created() {
    this.goodsId = Number(this.$route.query.goodsId)
    this.getGoodsDetails(Number(this.$route.query.goodsId))
    this.getCate()
  },
  mounted() {}
}
</script>

<style lang="scss" scoped>
    h3{
        position: relative;
        font-size: 16px;
        font-weight: normal;
        padding-left: 8px;
        margin-bottom: 20px;
    }
    h3::before{
        content: '';
        display: block;
        position: absolute;
        left: 0;
        top: 50%;
        transform: translateY(-50%);
        width: 2px;
        height: 16px;
        background: #1890ff;
    }
    h3::after{
        content: '';
        display: block;
        position: absolute;
        width: calc(100% - 90px) ;
        height: 1px;
        background: #ddd;
        right: 10px;
        top: 50%;
        transform: translateY(-50%);
    }
    .el-form-item {
        width: 100%;
    }
    ::v-deep  .el-upload{
        width: 100px;
        height: 100px;
        line-height: 100px;
        border: 1px solid #ddd;
    }
    ::v-deep .el-form-item__content {
        display: flex;
        line-height: 36px;
    }
    ::v-deep .switchStyle {
        height: 38px;
    }
    ::v-deep .switchStyle .el-switch__label {
        position: absolute;
        display: none;
        color: #fff;
      }
      ::v-deep .switchStyle .el-switch__label--left {
        z-index: 9;
        left: 19px;
      }
      ::v-deep .switchStyle .el-switch__label--right {
        z-index: 9;
        left: -2px;
      }
      ::v-deep .el-switch__label.is-active {
        display: block;
      }
      ::v-deep .el-switch .el-switch__core,
      .el-switch .el-switch__label {
        width: 60px !important;
      } 
</style>